/***************************************************************************//**
 * @file bsp_BL55072A。c
 * @brief for mac
 * @author ze .
 * @date  2022/9/25.
 * @copyright Copyright
 ******************************************************************************/
#include "bsp_BL55072A.h"
#include "bsp_gpio.h"
#include "softwareMultiTimer.h"
#include "bsp_SHT20.h"

uint8 idata LcdDisDataBuffer[LCD_DIS_BUF_LEN]= {0};
uint8 xdata LCD_DIS_Flag;

const uint8 xdata charater_table[]=
{
    0x5F,0x06,0x3D,0x2F,0x66,0x6B,0x7B,0x0E,0x7F,0x6F,     //温湿度断码显示0-9
    0x7E,0x73,0x59,0x37,0x79,0x78,0x58,0x00    //A-F r

};

const uint8 xdata charater_point_table[]=
{
    0xAF,0x06,0x6D,0x4F,0xC6,0xCB,0xEB,0x0E,0xEF,0xCF,    //温湿度小数点断码显示0-9
    0xEE,0xE3,0xA9,0x67,0xE9,0xE8,0xA8     //A-F r

};
#define I2C_WR	0		/* 写控制bit */
#define I2C_RD	1		/* 读控制bit */

static ds_gpio_t SCLGpio =
    {
//        .port = gpioPortC,
//        .pin = 2,
        .port = gpioPortA,
        .pin = 8,
        .mode = gpioModePushPull,
        .initial = 0,
        .valid = 1,
    };

static ds_gpio_t SDAGpio =
    {
//        .port = gpioPortC,
//        .pin = 3,
        .port = gpioPortD,
        .pin = 3,
        .mode = gpioModeInput,
        .initial = 0,
        .valid = 1,
    };


/* 定义读写SCL和SDA的宏 */
#define I2C_SCL_1()  ds_gpio_set(&SCLGpio)        /* SCL = 1 */ //PD1
#define I2C_SCL_0()  ds_gpio_clear(&SCLGpio)      /* SCL = 0 */

#define I2C_SDA_1()  ds_gpio_set(&SDAGpio)      /* SDA = 1 */ //PD3
#define I2C_SDA_0()  ds_gpio_clear(&SDAGpio)    /* SDA = 0 */

#define I2C_SDA_READ()  ds_gpio_read(&SDAGpio)  /* 读SDA口线状态 */
//#define I2C_SCL_READ()  ds_gpio_read()  /* 读SCL口线状态 */

/* 切换GPIO输入/输出 */
#define I2C_SDA_IN()  {SDAGpio.mode = gpioModeInput; ds_gpio_init(&SDAGpio);}
#define I2C_SDA_OUT() //每次输出均修改模式，无需提前修改输出模式 /*推挽输出*/


enum
{
 RSSI_ICON_STATE_IDLE = 0,
 RSSI_ICON_STATE_REGISTING ,
 RSSI_ICON_STATE_REGISTER_SUCC,
 RSSI_ICON_STATE_REGISTER_FAILED
};

typedef struct
{
  uint8_t byBattLevel;// 0 1 2 3 4

  uint8_t byRssiLevel;// 0 1 2 3 4
  uint8_t byRssiLevelBackUp; //其他Rssi状态打断后恢复用
  uint8_t byRssiIconState; //
  uint8_t byRssiFlashDownCount;// 该值 为亮-灭的次数*2
}LCD_ICON_CTRL_ST;

static LCD_ICON_CTRL_ST stLcdIconCtrl=
{
    .byBattLevel = 4,
    .byRssiLevel = 0,
    .byRssiLevelBackUp = 0,
    .byRssiIconState = RSSI_ICON_STATE_IDLE,
    .byRssiFlashDownCount = 0
};

static MultiTimer LcdCtrlDelayTime = {.Handle = 0xFF11};
//EN_LP_HARD_TIMER_EM3_SYS_RTC_1
static bool isLcdCtrlDelayTimeExpired = false;
static bool isTempUintC = true; //默认规格为摄氏度；
//001 – 0.5 Hz
//010 – 1 Hz
//011 – 2 Hz
//100 – 0.3 Hz
//101 – 0.2 Hz
#define BLINK_FREQ_INVALID  0xF0
static uint8_t s_screenBlinkFreq = BLINK_FREQ_INVALID ; //0表示 常显示 最大 101(B) //无效值为0xF0

void BL55072A_DisOn(void);
void i2c_Stop(void);     

//Rssi信号图标专用，不能和其冲突
void LcdCtrlDelayTimeCallback(struct MultiTimerHandle* timeHandle,void* pData)
{
  (void) timeHandle;
  (void) pData;
  LCD_DIS_Flag = 1;//需刷新Lcd屏幕显示
  isLcdCtrlDelayTimeExpired = true;
}

void lcdRssiIconRegHandle()
{
  static uint8_t sRssiIconRegisterCount = 0;

  if(!isLcdCtrlDelayTimeExpired)
  {
    return;
  }

  isLcdCtrlDelayTimeExpired = false;
  if(stLcdIconCtrl.byRssiIconState == RSSI_ICON_STATE_REGISTING)
    {
      stLcdIconCtrl.byRssiLevel ++ ;
      if(stLcdIconCtrl.byRssiLevel > 4)
        stLcdIconCtrl.byRssiLevel = 1; //轮番变化
      //重新开始200ms周期
      softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1,&LcdCtrlDelayTime,6554, LcdCtrlDelayTimeCallback, NULL ,1);//200ms
    }
  else if(stLcdIconCtrl.byRssiIconState == RSSI_ICON_STATE_REGISTER_SUCC)
    {
      //注册成功闪烁次数控制
      if(sRssiIconRegisterCount ++ < 14)
      {
        if(sRssiIconRegisterCount & 0x01)
        {
           stLcdIconCtrl.byRssiLevel = 4;
        }
        else
        {
            stLcdIconCtrl.byRssiLevel = 0;
        }
        //重新开始500ms周期
        softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1,&LcdCtrlDelayTime,16384, LcdCtrlDelayTimeCallback, NULL ,1);//500ms
      }
      else
      {
        sRssiIconRegisterCount = 0;
        stLcdIconCtrl.byRssiIconState = RSSI_ICON_STATE_IDLE;
        stLcdIconCtrl.byRssiLevel = stLcdIconCtrl.byRssiLevelBackUp; //恢复
      }
    }
  else if(stLcdIconCtrl.byRssiIconState == RSSI_ICON_STATE_REGISTER_FAILED)
    {
      stLcdIconCtrl.byRssiIconState = RSSI_ICON_STATE_IDLE;
      stLcdIconCtrl.byRssiLevel = stLcdIconCtrl.byRssiLevelBackUp; //恢复
    }

  else if(stLcdIconCtrl.byRssiFlashDownCount > 0)
    {
      if(stLcdIconCtrl.byRssiFlashDownCount & 0x01)//奇数灭
        {
          stLcdIconCtrl.byRssiLevel = 0;
        }
      else //偶数亮
        {
          stLcdIconCtrl.byRssiLevel = stLcdIconCtrl.byRssiLevelBackUp;
        }

      //重新开始500ms周期
      softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1,&LcdCtrlDelayTime,8192, LcdCtrlDelayTimeCallback, NULL ,1);//250ms-250ms
      stLcdIconCtrl.byRssiFlashDownCount --;
    }
}

void LcdRssiFlashCtrl(uint8_t times)//控制闪烁关闭后，将RSSI显示恢复为备份值，当前为500ms周期
{
  if(times > 128)
    times = 128;
  stLcdIconCtrl.byRssiFlashDownCount = times*2;
  stLcdIconCtrl.byRssiLevel = stLcdIconCtrl.byRssiLevelBackUp;
  isLcdCtrlDelayTimeExpired = true;
  LCD_DIS_Flag=1;//即刻刷新显示
}

//该标志阻止休眠
uint8_t getLcdWorkFlag()
{
  return LCD_DIS_Flag;
}

void LcdBattLevelSet(uint8_t battLevel)
{
  if(battLevel > 4)
  {
    printf("[ERR] batt level %d \r\n",battLevel);
    battLevel = 4;
  }
  if(battLevel != stLcdIconCtrl.byBattLevel)
  {
    LCD_DIS_Flag = 1;
  }

  stLcdIconCtrl.byBattLevel = battLevel;
}

void LcdRssiLevelSet(uint8_t rssiLevel)
{
  if(rssiLevel > 4)
  {
    printf("[ERR] Rssi level%d \r\n",rssiLevel);
    rssiLevel = 4;
  }

  stLcdIconCtrl.byRssiLevelBackUp = rssiLevel;//每次均备份RSSI值
  if(stLcdIconCtrl.byRssiIconState != RSSI_ICON_STATE_IDLE)//当前图标正在被 闪烁等 控制，暂时不展示信号强度，等待闪烁控制结束后，恢复backUp的值
  {

  }
  else
  {
    if(rssiLevel != stLcdIconCtrl.byRssiLevel)
    {
      LCD_DIS_Flag = 1;
    }
    stLcdIconCtrl.byRssiLevel = rssiLevel;
  }
}

void LcdRegistingStart()
{
  stLcdIconCtrl.byRssiIconState = RSSI_ICON_STATE_REGISTING;
  stLcdIconCtrl.byRssiLevel = 0;
  softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1,&LcdCtrlDelayTime,6554, LcdCtrlDelayTimeCallback, NULL ,1);//200ms

}

void LcdRegistFinish(bool isSucc)
{
  if(isSucc)
    stLcdIconCtrl.byRssiIconState = RSSI_ICON_STATE_REGISTER_SUCC;
  else
    stLcdIconCtrl.byRssiIconState = RSSI_ICON_STATE_REGISTER_FAILED;

  stLcdIconCtrl.byRssiLevel = 0;
  softwareMultiTimerStart(EN_LP_HARD_TIMER_EM3_SYS_RTC_1,&LcdCtrlDelayTime,16384, LcdCtrlDelayTimeCallback, NULL ,1);//200ms
}
/*
*********************************************************************************************************
*	函 数 名: i2c_Delay
*	功能说明: I2C总线位延迟，最快400KHz
*	形    参:  无
*	返 回 值: 无
*********************************************************************************************************
*/
void i2c_Delay(void)
{
	uint8 i;

	/*　
		CPU主频72MHz时，在内部Flash运行, MDK工程不优化。用台式示波器观测波形。
		循环次数为30时，SCL频率 = 440KHz， SCL高电平时间4us，SCL低电平时间8us
		上拉电阻选择2.2K欧时，SCL上升沿时间约0.5us，如果选4.7K欧，则上升沿约1us
		实际应用选择400KHz左右的速率即可
		230927，更换平台后待实测！
	*/
	for (i = 0; i < 1; i++)
      {

      }

}

/*
*********************************************************************************************************
*	函 数 名: i2c_Start
*	功能说明: CPU发起I2C总线启动信号
*	形    参:  无
*	返 回 值: 无
*********************************************************************************************************
*/
void i2c_Start(void)
{
	/* 当SCL高电平时，SDA出现一个下跳沿表示I2C总线启动信号 */
	I2C_SDA_OUT();
	
	I2C_SDA_1();
	I2C_SCL_1();
	i2c_Delay();
	I2C_SDA_0();
	i2c_Delay();
	
	I2C_SCL_0();
	i2c_Delay();
}

/*
*********************************************************************************************************
*	函 数 名: i2c_Start
*	功能说明: CPU发起I2C总线停止信号
*	形    参:  无
*	返 回 值: 无
*********************************************************************************************************
*/
void i2c_Stop(void)
{
	/* 当SCL高电平时，SDA出现一个上跳沿表示I2C总线停止信号 */
	
	I2C_SDA_OUT();
	
	I2C_SDA_0();
	I2C_SCL_1();
	i2c_Delay();
	I2C_SDA_1();
	i2c_Delay();
}

/*
*********************************************************************************************************
*	函 数 名: i2c_SendByte
*	功能说明: CPU向I2C总线设备发送8bit数据
*	形    参:  _ucByte ： 等待发送的字节
*	返 回 值: 无
*********************************************************************************************************
*/
void i2c_SendByte(uint8 _ucByte)
{
	uint8 i;

	I2C_SDA_OUT();
	/* 先发送字节的高位bit7 */
	for (i = 0; i < 8; i++)
	{
		if (_ucByte & 0x80)
		{
			I2C_SDA_1();
		}
		else
		{
			I2C_SDA_0();
		}
		i2c_Delay();
		I2C_SCL_1();
		i2c_Delay();
		I2C_SCL_0();
		if (i == 7)
		{
			 I2C_SDA_1(); // 释放总线
		}
		_ucByte <<= 1;	/* 左移一个bit */
		//i2c_Delay();
	}
}


/*
*********************************************************************************************************
*	函 数 名: i2c_WaitAck
*	功能说明: CPU产生一个时钟，并读取器件的ACK应答信号
*	形    参:  无
*	返 回 值: 返回0表示正确应答，1表示无器件响应
*********************************************************************************************************
*/
uint8 i2c_WaitAck(void)
{

	uint8 re;
#if 0
	I2C_SDA_OUT();
	I2C_SDA_1();	/* CPU释放SDA总线 */
#endif
	I2C_SDA_IN();
	
	//i2c_Delay();
	I2C_SCL_1();	/* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
	i2c_Delay();
	if (I2C_SDA_READ())	/* CPU读取SDA口线状态 */
	{
		re = 1;
	}
	else
	{
		re = 0;
	}
	I2C_SCL_0();
	//i2c_Delay();

	//printf("-%d\r\n",re);
	return re;
}



/********************************************************
函数名称：void BL55072A_Init(void)
功能描述: BL55072A初始化
全局变量：无
参数说明：无
返回说明：无
版 本：1.0
说 明：初始化后，液晶屏所有字段均显示
********************************************************/

void BL55072A_Init(void)
{
		uint8 i,ack;
		
		ds_gpio_init(&SCLGpio);//每次输出均已初始化

	i2c_Start();//发送IIC开始信号
    i2c_SendByte(BL55072A_ADR_W);//0x7C  IIC发送一个字节
    ack = i2c_WaitAck();
	
	i2c_SendByte(ICSET_MSB);// 0xE8 IIC发送一个字节
    ack = i2c_WaitAck();
	
	i2c_SendByte(MODESET);//  0xC8   IIC发送一个字节
    ack = i2c_WaitAck();
	
    i2c_SendByte(BLKCTL);// 0xF0  IIC发送一个字节
    ack = i2c_WaitAck();

    i2c_SendByte(DISCTL);//0xA2   IIC发送一个字节
    ack = i2c_WaitAck();

	 i2c_SendByte(ADSET);//0x00  IIC发送一个字节
    ack = i2c_WaitAck();
	
	for (i = 0; i < LCD_DIS_BUF_LEN; i++)
	{
		i2c_SendByte(0xFF);//全部显示
		ack = i2c_WaitAck();
	}
	i2c_Stop();

	LCD_DIS_Flag=1;

}


/**********测试全部点亮******/
//ctrl: 0退出全屏控制  1全亮  2全灭
void LCD_DIS_all(uint8_t ctrl)
{
    uint8 ack = 0;
    uint8_t apctl;
    if(ctrl == 0)
      apctl = 0xFC;
    else if (ctrl == 1)
      apctl = APCTL;
    else if (ctrl == 2)
      apctl = 0xFD;

    i2c_Start();//发送IIC开始信号
    i2c_SendByte(BL55072A_ADR_W);//0x7C    IC发送一个字节
    ack = i2c_WaitAck();
    i2c_SendByte(apctl);  //0xFE   IIC发送一个字节
    ack = i2c_WaitAck();
    i2c_SendByte(MODESET);//IIC发送一个字节
    ack = i2c_WaitAck();
    i2c_Stop();
}

/*************************************************
函数功能：
函数名称:全屏闪烁
形参：开启、关闭
返回无 #define BLINK_FREQ_INVALID  0xF0
*************************************************/
void LCD_blink_ctrl(bool isOn)
{
  if(isOn)
    {
      s_screenBlinkFreq = 0x03;//2Hz
    }
  else
    {
      s_screenBlinkFreq = 0x00;//关闭
    }
  LCD_DIS_Flag=1;
}

/*************************************************
函数功能：
函数名称:void LCD_DIS_battery(uint8 level)
形参：0：空格 1:1格  2：两格  3:3格  4:4格 5:5格
返回无
*************************************************/
void LCD_DIS_battery(uint8 level)
{
    LcdDisDataBuffer[7] &= 0xF0;//
    switch (level)
    {
		case 1: //1 level
			LcdDisDataBuffer[7]|=0x01;
			break;
		case 2:  //2 level
			LcdDisDataBuffer[7]|=0x03;

			break;
		case 3:  //3 level
			LcdDisDataBuffer[7]|=0x07;
			break;
		case 4:  //4 level
			LcdDisDataBuffer[7]|=0x0F;
			break;
    }
}

/********************************************************
函数功能：显示移动信号网络图标
函数名称：
形参 level ：信号等级强弱 1-4 1最弱  0不显示

********************************************************/
void LCD_Dis_rssi(uint8 level)
{
  LcdDisDataBuffer[6]&= 0xF0;
  switch (level)
  {
  case 0: //0 格

    break;
  case 1: //1 level
    LcdDisDataBuffer[6] |= 0x08; //
    break;
  case 2:  //2 level
    LcdDisDataBuffer[6] |= 0x0C;
    break;
  case 3:  //3 level
    LcdDisDataBuffer[6] |= 0x0E;
    break;
  case 4:  //4 level
    LcdDisDataBuffer[6] |= 0x0F;
    break;
  default:
    break;
  }
}


void LcdTempUnitSet(bool isC)
{
  if(isTempUintC != isC)
    LCD_DIS_Flag=1;

  isTempUintC = isC;
}


/**********************************************************
函数功能:
函数名称:  LCD_Dis_Line
形参:type  0:不显示   1：显示
返回:无
其它:
***********************************************************/
void LCD_Dis_Line(uint8 state)
{
    if(state==1)
    {
        LcdDisDataBuffer[3]|=0x10;
    }
	else
	{
		LcdDisDataBuffer[3]&=0xEF;
	}
}


/*************************************************
函数功能：显示 湿度 数值
函数名称: void New_LCD_Dis_Hum_Num(float num)
形参：num:要显示的数值,0xff:清除所有显示
返回：无
*************************************************/
void New_LCD_Dis_Hum_Num(int16_t num)
{
  uint8 point;
  uint8 shi;
  uint8 ge;
  uint16 tempdata;
  tempdata = (uint16_t )(num);
	printf("Humi:%d\r\n",num);
//清除之前的显示
  LcdDisDataBuffer[0] = 0x00;
  LcdDisDataBuffer[1] = 0x00;
  LcdDisDataBuffer[2] = 0x00;

  point = tempdata%10;
  ge=(tempdata%100)/10;
  shi=tempdata/100;
  //十位
  LcdDisDataBuffer[0]=charater_table[shi];
  //个位
  LcdDisDataBuffer[1]=charater_table[ge];
  //小数点位
  LcdDisDataBuffer[2]=charater_point_table[point];

  LcdDisDataBuffer[0] |= 0x80; //湿度图标
  LcdDisDataBuffer[1] |= 0x80; //湿度百分比图标
  LcdDisDataBuffer[2] |= 0x10;//显示小数点
}
/*************************************************
函数功能：显示 温度 数值
函数名称: void New_LCD_Dis_Tem_Num(uint8 num)
形参：num:要显示的数值, 0xffff:清除所有显示
返回：无
*************************************************/
void New_LCD_Dis_Tem_Num(int16_t num)
{
  uint8 bai;
  uint8 shi;
  uint8 ge;
  uint8 point;
  int16_t  temp;

	printf("Temp:%d \r\n",num);

  if(!isTempUintC)//华氏度显示，将摄氏度转成华氏
    num = num*9/5 + 320; //最大值364.0摄氏度可转

  //清除之前的显示
  LcdDisDataBuffer[3] =0x00;
  LcdDisDataBuffer[4] =0x00;
  LcdDisDataBuffer[5] =0x00;
  LcdDisDataBuffer[6] =0x00;
	
	if (num < 0)
	{
		temp = -num;
	}
	else
	{
		temp = num;
	}

  point=temp%10;
  ge=temp%100/10;
  shi=temp%1000/100;
  bai=temp/1000;//仅支持百位数为1，超过后仍将显示1

  if(bai > 1){ //超显示量程，满偏显示
    bai = 1;
    shi = 9;
    ge = 9;
    point = 9;
  }

  LcdDisDataBuffer[3] = charater_table[shi] >> 4;
  LcdDisDataBuffer[4] = (charater_table[shi]<<4)+(charater_table[ge]>>4);
  LcdDisDataBuffer[5] = (charater_table[ge]<<4)+(charater_point_table[point]>>4);
  LcdDisDataBuffer[5] |= 0x01;	//显示小数点
  LcdDisDataBuffer[6] = charater_point_table[point]<<4;

  if(num<0)
  {
      LcdDisDataBuffer[3] |= 0x40;//显示负号
  }

  LcdDisDataBuffer[7] &= 0x0F; //先清除温度百位和摄氏度单位显示
  if(bai == 1)
  {
      LcdDisDataBuffer[7] |= 0x30;//显示百位数
  }

  if(isTempUintC)//摄氏度
    LcdDisDataBuffer[7] |= 0x40;
  else //华氏度
    LcdDisDataBuffer[7] |= 0x80;

	LcdDisDataBuffer[3] |= 0xB0; //0x10 横线、 0x20 温度图标、 0x80 电池外框图标
	LcdDisDataBuffer[4] |= 0x08; //摄氏度/华氏度 公共部分图标1半

}

void BL55072A_DisOn(void)
{
    uint8 ack = 0;
    i2c_Start();//发送IIC开始信号
    i2c_SendByte(BL55072A_ADR_W);//IIC发送一个字节
    ack = i2c_WaitAck();
    i2c_SendByte(MODESET);//IIC发送一个字节
    ack = i2c_WaitAck();
    i2c_Stop();
}

void BL55072A_DisTR(void)
{
  uint8 ack;
  uint8 i;

  if(LCD_DIS_Flag)
  {
    LCD_DIS_Flag=0;
    lcdRssiIconRegHandle();

    New_LCD_Dis_Tem_Num(getCurrentTemp());
    New_LCD_Dis_Hum_Num(getCurrentHumi());

    LCD_DIS_battery(stLcdIconCtrl.byBattLevel); //更新电池图标
    LCD_Dis_rssi(stLcdIconCtrl.byRssiLevel); //更新信号强度图标

    i2c_Start();//发送IIC开始信号
    i2c_SendByte(BL55072A_ADR_W);//0x7C  IIC发送一个字节
    ack = i2c_WaitAck();

    i2c_SendByte(ICSET_MSB);// 0xE8 IIC发送一个字节
    ack = i2c_WaitAck();

    i2c_SendByte(MODESET);//  0xC8   IIC发送一个字节
    ack = i2c_WaitAck();

    if(BLINK_FREQ_INVALID != s_screenBlinkFreq)
    {
      i2c_SendByte(BLKCTL | s_screenBlinkFreq);// 0xF0  IIC发送一个字节，闪烁控制
      ack = i2c_WaitAck();
      s_screenBlinkFreq = BLINK_FREQ_INVALID; //
    }

    i2c_SendByte(ADSET);//0x00  IIC发送一个字节
    ack = i2c_WaitAck();

    for (i = 0; i < LCD_DIS_BUF_LEN; i++)
    {
      i2c_SendByte(LcdDisDataBuffer[i]);//全部显示
      ack = i2c_WaitAck();
    }

     i2c_Stop();
     BL55072A_DisOn();

  }
}

